﻿using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Threading;
using System.Windows;
using Google.AdMob.Ads.WindowsPhone7;
using Google.AdMob.Ads.WindowsPhone7.WPF;
using MC.Phone.Ads.Provider;
using MC.Phone.Ads.Utils;
using Microsoft.Phone.Info;

namespace MC.Phone.Ads.AdMob
{
    public class AdMobAdProvider : BaseAdProvider
    {
        public static readonly DependencyProperty AdUnitProperty =
            DependencyProperty.Register("AdUnit", typeof (string), typeof (AdMobAdProvider), null);

        private WeakEventListener<AdMobAdProvider, object, RoutedEventArgs> _adReceivedListener;
        private WeakEventListener<AdMobAdProvider, object, AdException> _adFailedListener;
        private WeakEventListener<AdMobAdProvider, object, RoutedEventArgs> _adPresentingScreenListener;
        private WeakEventListener<AdMobAdProvider, object, RoutedEventArgs> _adLeavingApplicationListener;

        public override string Name
        {
            get { return "AdMob"; }
        }

        /// <summary>
        /// Note the testmode is automatically set in the following occasions:
        /// - If AdUnit isn't set
        /// - If the IsTest is set, either on the adprovider or on the adcontrol
        /// - If the application is run on the emulator
        /// - If the debugger is attached
        /// </summary>
        public override bool IsTest { get; set; }

        [Category("Ad")]
        public string AdUnit
        {
            get { return (string) GetValue(AdUnitProperty); }
            set { SetValue(AdUnitProperty, value); }
        }

        public override FrameworkElement ProvideAd()
        {
            if (string.IsNullOrEmpty(AdUnit))
            {
                string message = "Please include a correct \'AdUnit\'.";
                if (IsTest)
                {
                    message = string.Format("{0} Also in TestMode.", message);
                }
                throw new Exception(message);
            }
            
            var control = new BannerAd
                              {
                                  AdUnitID = AdUnit,
                                  LocationDescription = CountryCode,
                                  Visibility = Visibility.Collapsed,
                              };
            if (IsTest)
            {
                control.TestDeviceIDs.Add(
                    Convert.ToBase64String((byte[]) DeviceExtendedProperties.GetValue("DeviceUniqueId")));
            }
            _adReceivedListener = new WeakEventListener<AdMobAdProvider, object, RoutedEventArgs>(this)
                                      {
                                          OnEventAction = (instance, source, args) => instance.AdReceived(source),
                                          OnDetachAction = weak => control.AdReceived -= weak.OnEvent
                                      };
            control.AdReceived += _adReceivedListener.OnEvent;

            _adFailedListener = new WeakEventListener<AdMobAdProvider, object, AdException>(this)
                                    {
                                        OnEventAction = (instance, source, args) => instance.AdFailed(source, args),
                                        OnDetachAction = weak => control.AdFailed -= weak.OnEvent
                                    };
            control.AdFailed += _adFailedListener.OnEvent;

            _adPresentingScreenListener = new WeakEventListener<AdMobAdProvider, object, RoutedEventArgs>(this)
                                              {
                                                  OnEventAction =
                                                      (instance, source, args) => instance.AdPresentingScreen(),
                                                  OnDetachAction = weak => control.AdPresentingScreen -= weak.OnEvent
                                              };
            control.AdPresentingScreen += _adPresentingScreenListener.OnEvent;

            _adLeavingApplicationListener = new WeakEventListener<AdMobAdProvider, object, RoutedEventArgs>(this)
                                                {
                                                    OnEventAction =
                                                        (instance, source, args) =>
                                                        instance.AdLeavingApplication(source, args),
                                                    OnDetachAction =
                                                        weak => control.AdLeavingApplication -= weak.OnEvent
                                                };
            control.AdLeavingApplication += _adLeavingApplicationListener.OnEvent;

            control.AdLeavingApplication += AdLeavingApplication;
            return control;
        }

        public override void Clean()
        {
            _adFailedListener = _adFailedListener.DetachToNull();
            _adLeavingApplicationListener = _adLeavingApplicationListener.DetachToNull();
            _adPresentingScreenListener = _adPresentingScreenListener.DetachToNull();
            _adReceivedListener = _adReceivedListener.DetachToNull();
        }

        private void AdReceived(object sender)
        {
            var adControl = (sender as BannerAd);
            if (adControl != null)
                adControl.Visibility = Visibility.Visible;
            OnNewAd();
        }

        private void AdFailed(object sender, AdException exception)
        {
            if (exception.ErrorCode == ErrorCode.NoFill)
            {
                var adControl = (sender as BannerAd);
                if (adControl != null)
                    adControl.Visibility = Visibility.Collapsed;
                OnNoAd();
            }
            else
            {
                OnAdError(exception);
            }
        }

        private void AdPresentingScreen()
        {
            OnAdEngaged();
        }

        private void AdLeavingApplication(object sender, RoutedEventArgs e)
        {
            OnAdEngaged();
        }

        
#if DEBUG
        ~AdMobAdProvider()
        {
            Debug.WriteLine( Thread.CurrentThread.ManagedThreadId + "--Finalizing " + GetType().FullName);
        }
#endif
    }
}